package log

//HandlerCommon common config info of handler
type HandlerCommon struct {
	//seperator char between message field.
	Sep string
	//seperator char in format message field.
	SepFmt string

	//time format function bond with handler.
	TimeFmt FuncTimeFmt

	//outputting target list.
	Targets []Target

	//prefixes
	Prefixes [][2]string
	//prefix string cache
	PrefixStr string

	//switch of code line outputting
	BCodeLine bool

	//switch of JSON assemble using
	UseJSONAssemble bool
}

//updatePrefixString update prefix string
func (h *HandlerCommon) updatePrefixString() {
	if len(h.Prefixes) != 0 {
		h.PrefixStr = ""
		for _, pr := range h.Prefixes {
			h.PrefixStr += h.Sep + pr[1]
		}
	} else {
		h.PrefixStr = ""
	}
}

//Handler is the builtin implement for LoggerHandler.
type Handler struct {
	//handler config
	common *HandlerCommon

	//handler log level
	level int

	ctxPool     *ContextPool
	ctxPoolSize int
}

//NewHandler return a Handler instance
//as a LoggerHandler interface instance.
func NewHandler() LoggerHandler {
	return NewHandlerWithConfig(globalHandlerConfig)
}

//NewHandlerWithConfig make a new Handler instance with configuration.
func NewHandlerWithConfig(cfg *HandlerConfig) *Handler {
	h := &Handler{
		common: &HandlerCommon{
			Sep:       cfg.Seperator,
			SepFmt:    cfg.FmtSeperator,
			TimeFmt:   BuiltinTimeFmtStandard,
			Targets:   append(make([]Target, 0, 4), defaultTargets...),
			Prefixes:  make([][2]string, 0, 4),
			PrefixStr: "",

			BCodeLine:       cfg.BCodeLine,
			UseJSONAssemble: cfg.BUseJSONAssemble,
		},

		level: cfg.Level,

		ctxPoolSize: cfg.ContextPoolSize,
	}
	h.ctxPool = NewContextPool(h.common, h.ctxPoolSize)
	return h
}

//Clone implement for LoggerHandler.Clone()
func (h *Handler) Clone() LoggerHandler {
	nh := &Handler{
		common: &HandlerCommon{
			Sep:       h.common.Sep,
			SepFmt:    h.common.SepFmt,
			TimeFmt:   h.common.TimeFmt,
			Targets:   make([]Target, 0, len(h.common.Targets)),
			Prefixes:  make([][2]string, len(h.common.Prefixes)),
			PrefixStr: h.common.PrefixStr,

			BCodeLine:       h.common.BCodeLine,
			UseJSONAssemble: h.common.UseJSONAssemble,
		},
		level:       h.level,
		ctxPoolSize: h.ctxPoolSize,
	}
	for i, p := range h.common.Prefixes {
		nh.common.Prefixes[i] = [2]string{p[0], p[1]}
	}
	nh.ctxPool = NewContextPool(nh.common, nh.ctxPoolSize)
	for _, t := range h.common.Targets {
		nh.AddTarget(t)
	}
	return nh
}

//BindTimeFmt implement for LoggerHandler.BindTimeFmt()
func (h *Handler) BindTimeFmt(f FuncTimeFmt) {
	h.common.TimeFmt = f
}

//SetSeperator implement for LoggerHandler.SetSeperator()
func (h *Handler) SetSeperator(sep string) {
	h.common.Sep = sep
	h.common.updatePrefixString()
}

//Level implement for LoggerHandler.Level()
func (h *Handler) Level() int {
	return h.level
}

//SetLevel implement for LoggerHandler.SetLevel()
func (h *Handler) SetLevel(l int) {
	h.level = l
}

//AddTarget implement for LoggerHandler.AddTarget()
func (h *Handler) AddTarget(t Target) {
	t.IncrUsing()
	h.common.Targets = append(h.common.Targets, t)
}

//DelTarget implement for LoggerHandler.DelTarget()
func (h *Handler) DelTarget(name string) {
	for i, t := range h.common.Targets {
		if t.Name() == name {
			h.common.Targets = append(h.common.Targets[:i], h.common.Targets[i+1:]...)
			break
		}
	}
}

//AddPrefix implement for LoggerHandler.AddPrefix()
func (h *Handler) AddPrefix(key, val string) {
	h.DelPrefix(key)
	h.common.Prefixes = append(h.common.Prefixes, [2]string{key, val})
	h.common.updatePrefixString()
}

//DelPrefix implement for LoggerHandler.DelPrefix()
func (h *Handler) DelPrefix(key string) {
	for i, v := range h.common.Prefixes {
		if key == v[0] {
			h.common.Prefixes = append(h.common.Prefixes[:i], h.common.Prefixes[i+1:]...)
			h.common.updatePrefixString()
			return
		}
	}
}

//SwitchCodeLine implement for LoggerHandler.SwitchCodeLine
func (h *Handler) SwitchCodeLine(b bool) {
	h.common.BCodeLine = b
}

//SwitchJSONAssemble implement for LoggerHandler.SwitchJSONAssemble
func (h *Handler) SwitchJSONAssemble(b bool) {
	h.common.UseJSONAssemble = b
}

//getContext get new context from handler
func (h *Handler) getContext(level int) ContextAllowTar {
	return h.ctxPool.Get(level)
}

//Release implement for LoggerHandler.Release()
func (h *Handler) Release() {
	for _, t := range h.common.Targets {
		t.Close()
	}
}

//Ctx implement for Logger.Ctx()
func (h *Handler) Ctx() ContextAllowTar {
	if levelIgnoreGlobal(h.Level()) {
		return CtxNil
	}

	ctx := h.getContext(h.Level())
	return ctx
}

//TRC implement for Logger.TRC()
func (h *Handler) TRC() ContextAllowTar {
	if levelIgnoreGlobal(LvlTrace) {
		return CtxNil
	}

	ctx := h.getContext(LvlTrace)
	return ctx
}

//DBG implement for Logger.DBG()
func (h *Handler) DBG() ContextAllowTar {
	if levelIgnoreGlobal(LvlDebug) {
		return CtxNil
	}

	ctx := h.getContext(LvlDebug)
	return ctx
}

//INF implement for Logger.INF()
func (h *Handler) INF() ContextAllowTar {
	if levelIgnoreGlobal(LvlInfo) {
		return CtxNil
	}

	ctx := h.getContext(LvlInfo)
	return ctx
}

//WAR implement for Logger.WAR()
func (h *Handler) WAR() ContextAllowTar {
	if levelIgnoreGlobal(LvlWarning) {
		return CtxNil
	}

	ctx := h.getContext(LvlWarning)
	return ctx
}

//ERR implement for Logger.ERR()
func (h *Handler) ERR() ContextAllowTar {
	if levelIgnoreGlobal(LvlError) {
		return CtxNil
	}

	ctx := h.getContext(LvlError)
	return ctx
}

//FAT implement for Logger.FAT()
func (h *Handler) FAT() ContextAllowTar {
	if levelIgnoreGlobal(LvlFatal) {
		return CtxNil
	}

	ctx := h.getContext(LvlFatal)
	return ctx
}
